Hasta ahora, tu código probablemente está regado en uno o varios notebooks. La idea es, primero, recolectarlo en un lugar.

[1] Revisa la documentación sobre modules (módulos) en Julia. Crea un módulo que se llama Ising (o ModeloIsing, o algo por el estilo), en un archivo Ising.jl tal que puedas incluir el código (e.g. desde un notebook) con using Ising, y correrlo al llamar una sola función que acepte los parámetros importantes del modelo (tamaño de la caja, temperatura, etc.). [Se recomienda usar un editor que "sepa Julia", e.g. Juno, Sublime Text, Atom (o Emacs o Vim) para este propósito.]

[2] Escribe un "script" (programa corto con código de Julia) que toma los argumentos de la línea de comandos [en Julia, éstos se guardan en la variable ARGS, y produce los plots de la energía y magnetización en función de la temperatura.

Tests (pruebas)

Cuando uno escribe software científico, es de suma importancia (evidentemente) que el software funcione correctamente. Sin embargo, desgraciadamente es, al mismo tiempo ¡imposible garantizar que funcione correctamente! Lo más que podamos hacer es dar una cierta medida de confianza de esto. Una manera de hacerlo es el escribir tests (pruebas).

Los unit tests (pruebas unitarias) checan si las unidades del programa (básicamente, las funciones) hacen lo que deben hacer. En Julia, un paquete muy útil para escribir tests es FactCheck.jl.

[3] Revisa la documentación de FactCheck.jl. Escribe, en un archivo aparte, tests para tu código de Ising para asegurarte que estén bien las siguientes funciones (por ejemplo):

  • la función que calcule la energía de una configuración
  • la función que calcule la diferencia de energía
  • la función que calcule la probabilidad de aceptación, $\alpha$

Para hacerlo, escoge para cada función varias inputs (entradas / argumentos) de la función para los cuales conoces de antemano la respuesta correcta y checa si tu programa da los resultados esperados.

Tipos

Hasta ahora, no hay manera de hablar del "modelo de Ising" o del "método de Metropolis" en tu código --los conceptos están, de igual forma, regados por el programa. Julia permite llevar a cabo la programación orientada a objetos, al definir tus propios tipos nuevos.

Por ejemplo:


In [1]:
type Hola
    a::Int
    b
end

define un tipo nuevo de objeto, que se llama Hola. Especifica que un objeto de este tipo contendrá una propiedad a, que es, a fuerzas, de tipo Int, y otro objeto b, que puede ser de cualquier tipo.

[4] Encuentra la manera de crear un objeto nuevo de este tipo.

[5] ¿Cuáles elementos de tu programa podrías tratar como objetos de esta forma? ¿Cómo se deberían comunicar entre ellos? [Nota que ¡no necesariamente hay respuestas únicas ni evidentes a esta pregunta!]

[6] La programación orientada a objetos requiere la posibilidad de manipular los objetos, al llamar funciones que actúan con o en función de ellos. Por ejemplo, si uno tiene un tipo Configuracion, podría querer tener una función voltear que actúa sobre este objeto. ¿Cómo se puede hacer esto en Julia?

[7] Escribe una nueva versión de tu código, en el cual se separa los conceptos de esta manera.

Control de versiones

Es importante contar con una bitácora de la evolución de tu código (y notebooks, datos, etc.) Para esto, se utiliza un sistema de control de versiones. El más común hoy día es git. Luego debes guardar tus archivos, y la bitácora, en un lugar remoto, por ejemplo GitHub.

[8] Aprende a utilizar git, por ejemplo usando los primeros dos notebooks de este curso.

[9] Crea un repositorio para tus archivos y notebooks y empújalo a una cuenta en GitHub.

[10] Haz un "fork" del proyecto de alguien más y compara los códigos. Trabaja en equipo para mejorar los códigos y sube la nueva versión.

Adapta tus tests para el código ajeno ¡e intentar romperlo!

Profiling

El "profiling" (perfilamiento) es una manera de encontrar dónde se pasa más tiempo en tu programa.

Julia tiene un comando (macro) @time que permite ver cuánto tiempo pasa en una función dada, e.g.

@time run(100)

Regresa información sobre el tiempo total y la memoria utilizada.

[11] Compara el tiempo de los dos códigos con los mismos parámetros. Encuentra cuáles funciones son más lentas.

Julia tiene también @profile run(100) que recolecta información sobre las funciones en las cuales se pasó más tiempo durante la corrida:

@profile run(100)
Profile.print()

[12] Encuentra dónde pasa tiempo tu programa. ¿Hay alguna manera de acelerarlo?

Nótese que estas optimizaciones sólo se deben hacer después de que ya tengas una versión funcional (aún si lenta) del programa. git permite rastrear todas las versiones anteriores del programa.

Dijo Donald Knuth (uno de los computólogos más destacados del siglo XX): "La optimización prematura es la raíz de todos los males".